package java.nio.channels;

import java.io.Closeable;
import java.io.IOException;
import java.nio.channels.spi.SelectorProvider;
import java.util.Set;


/**
 * A multiplexor of {@link SelectableChannel} objects.
 * 多路复用器
 *
 * =========================================================================
 * <p> A selector may be created by invoking the {@link #open open} method of
 * this class, which will use the system's default {@link
 * java.nio.channels.spi.SelectorProvider selector provider} to
 * create a new selector.  A selector may also be created by invoking the
 * {@link java.nio.channels.spi.SelectorProvider#openSelector openSelector}
 * method of a custom selector provider.  A selector remains open until it is
 * closed via its {@link #close close} method.
 * 多路复用器通过如下方法创建：
 * 1、Selector selector = Selector.open();
 * // SelectorProvider.provider().openSelector();
 * 2、new SelectorProviderImpl().openSelector();
 *
 * =========================================================================
 * <p> A selectable channel's registration with a selector is represented by a
 * {@link SelectionKey} object.  A selector maintains three sets of selection
 * keys:
 * 可选择通道在多路复用器中的注册是通过SelectionKey对象表示的
 * 多路复用器维护了三个seletion keys的sets
 *
 * =========================================================================
 * 1、key set 包含着所有selectionKeys，当前所有注册到selector中的channel返回的注册关系SelectionKey都包含在内，这个集合可以通过selector.keys() 方法返回。
 * 2、selected-key set 包含着一部分selectionKeys，其中的每个selectionKey所关联的channel在selection operation期间被检测出至少 准备好 了一个可以在兴趣集中匹配到的操作。这个集合可以通过调用selector.selectedKeys()方法返回。selected-key set 一定是 key set 的子集。
 * 3、cancelled-key set 也包含着一部分selectionKeys，其中的每个selectionKey都已经被取消，但是所关联channel还没有被撤销登记。cancelled-key set 不能够被直接返回，但也一定是 key set 的子集。
 *
 *   <li><p> The <i>key set</i> contains the keys representing the current
 *   channel registrations of this selector.  This set is returned by the
 *   {@link #keys() keys} method. </p></li>
 *
 *   <li><p> The <i>selected-key set</i> is the set of keys such that each
 *   key's channel was detected to be ready for at least one of the operations
 *   identified in the key's interest set during a prior selection operation.
 *   This set is returned by the {@link #selectedKeys() selectedKeys} method.
 *   The selected-key set is always a subset of the key set. </p></li>
 *
 *   <li><p> The <i>cancelled-key</i> set is the set of keys that have been
 *   cancelled but whose channels have not yet been deregistered.  This set is
 *   not directly accessible.  The cancelled-key set is always a subset of the
 *   key set. </p></li>
 *
 * =========================================================================
 * 如何将selectable channel注册到selector中
 *    SelectionKey key = channel.register(selector,Selectionkey.XXX);
 *
 * =========================================================================
 * selector如何选择就绪channel
 * 每次 selection operation 期间， keys都可以添加到或从selector’s selected-key set 被移除，同时也可以从它的 key 和 cancelled-key sets 被移除。
 * selection operation 可以被触发通过执行selector.select()，selector.select(long)，和selector.selectNow() 方法，并且这些方法涉及到以下三个步骤：
 * 1、首先每个位于 cancelled-key set 中的key会从每个包含它的key集合中被移除，并且对应的channel会被撤销登记。这个步骤使得 cancelled-key set 变为空。
 * 2、查询底层操作系统来获得关于selector中剩余channel的就续事件从 selection operation 开始截止到此刻的更新情况，只要哪个channel的就续事件的更新部分有至少一个与兴趣集中的操作匹配上，那么将会执行以下两个动作：
 * 如果这个channel's key 没有存在 于 selected-key set 那么将它添加到这个集合中，并将它的就绪操作集(ready-operation set)修改成 只包含使得channel被报告就绪的操作，任何先前记录在就绪操作集中的就绪信息都会被丢弃。
 * 否则，如果这个channel's key 存在 于 selected-key set ，那么就保留就绪操作集中先前的就绪信息，并将这些 使得channel被报告就绪的操作 写入进去；总而言之，系统底层会通过按位与&操作更新当前就绪集。
 * 如果这些Key的兴趣集为空，那么 selected-key set 和 keys’的就续集(ready-operation sets)都不会被更新。
 * 3、如果在步骤（2）正在进行时将任何key添加到 cancelled-key set，则按步骤（1）处理它们。
 *
 * =========================================================================
 * 通过channel的register方法，一个selectionKey被增加到selector的 key set 中。
 * 无论通过channel.close()还是通过selectionKey.cancel()来取消一个selectionKey ，这个selectionKey都会被立即添加到selector的 cancelled-key set 中，但是所关联的channel并没有立即被撤销登记，直到发生下次 selection operations, 这些channel才被从selector中撤销登记，与此同时这些Cancelled keys才会被从这个selector的所有selectionKey set（可能是_key set_、selected-key set、cancelled-key set）中移除，但是不会影响这些集合本身。
 * 在 selection operations 期间，一些selectionKey会被选中添加到 selected-key set 中。其中的每个key可以通过selectiedKeys.remove()或selectiedKeys.iterator().remove()直接从 selected-key set 中移除，除此之外不能够通过任何方式被直接移除。特殊的，selected-key set 中的keys还可以在 selection operations 期间被间接移除。但是是不可以直接向 selected-key set 添加key的。
 *
 * =========================================================================
 * 如果一个线程在调用select()或select(long)方法时被阻塞，调用wakeup()会使线程立即从阻塞中唤醒；如果调用wakeup()期间没有select操作，下次调用select相关操作会立即返回，不会执行poll()，包括调用selectNow()。
 * 在Select期间，多次调用wakeup()与调用一次效果是一样的。
 *
 * @see SelectableChannel
 * @see SelectionKey
 */

public abstract class Selector implements Closeable {

    /**
     * Initializes a new instance of this class.
     */
    protected Selector() { }

    /**
     * Opens a selector.
     *
     * <p> The new selector is created by invoking the {@link
     * java.nio.channels.spi.SelectorProvider#openSelector openSelector} method
     * of the system-wide default {@link
     * java.nio.channels.spi.SelectorProvider} object.  </p>
     *
     * @return  A new selector
     *
     * @throws  IOException
     *          If an I/O error occurs
     */
    public static Selector open() throws IOException {
        return SelectorProvider.provider().openSelector();
    }

    /**
     * Tells whether or not this selector is open.
     *
     * @return <tt>true</tt> if, and only if, this selector is open
     */
    public abstract boolean isOpen();

    /**
     * Returns the provider that created this channel.
     *
     * @return  The provider that created this channel
     */
    public abstract SelectorProvider provider();

    /**
     * Returns this selector's key set.
     *
     * <p> The key set is not directly modifiable.  A key is removed only after
     * it has been cancelled and its channel has been deregistered.  Any
     * attempt to modify the key set will cause an {@link
     * UnsupportedOperationException} to be thrown.
     *
     * <p> The key set is <a href="#ksc">not thread-safe</a>. </p>
     *
     * @return  This selector's key set
     *
     * @throws  ClosedSelectorException
     *          If this selector is closed
     */
    public abstract Set<SelectionKey> keys();

    /**
     * Returns this selector's selected-key set.
     *
     * <p> Keys may be removed from, but not directly added to, the
     * selected-key set.  Any attempt to add an object to the key set will
     * cause an {@link UnsupportedOperationException} to be thrown.
     *
     * <p> The selected-key set is <a href="#ksc">not thread-safe</a>. </p>
     *
     * @return  This selector's selected-key set
     *
     * @throws  ClosedSelectorException
     *          If this selector is closed
     */
    public abstract Set<SelectionKey> selectedKeys();

    /**
     * Selects a set of keys whose corresponding channels are ready for I/O
     * operations.
     *
     * <p> This method performs a non-blocking <a href="#selop">selection
     * operation</a>.  If no channels have become selectable since the previous
     * selection operation then this method immediately returns zero.
     *
     * <p> Invoking this method clears the effect of any previous invocations
     * of the {@link #wakeup wakeup} method.  </p>
     *
     * @return  The number of keys, possibly zero, whose ready-operation sets
     *          were updated by the selection operation
     *
     * @throws  IOException
     *          If an I/O error occurs
     *
     * @throws  ClosedSelectorException
     *          If this selector is closed
     */
    public abstract int selectNow() throws IOException;

    /**
     * Selects a set of keys whose corresponding channels are ready for I/O
     * operations.
     *
     * <p> This method performs a blocking <a href="#selop">selection
     * operation</a>.  It returns only after at least one channel is selected,
     * this selector's {@link #wakeup wakeup} method is invoked, the current
     * thread is interrupted, or the given timeout period expires, whichever
     * comes first.
     *
     * <p> This method does not offer real-time guarantees: It schedules the
     * timeout as if by invoking the {@link Object#wait(long)} method. </p>
     *
     * @param  timeout  If positive, block for up to <tt>timeout</tt>
     *                  milliseconds, more or less, while waiting for a
     *                  channel to become ready; if zero, block indefinitely;
     *                  must not be negative
     *
     * @return  The number of keys, possibly zero,
     *          whose ready-operation sets were updated
     *
     * @throws  IOException
     *          If an I/O error occurs
     *
     * @throws  ClosedSelectorException
     *          If this selector is closed
     *
     * @throws  IllegalArgumentException
     *          If the value of the timeout argument is negative
     */
    public abstract int select(long timeout)
        throws IOException;

    /**
     * Selects a set of keys whose corresponding channels are ready for I/O
     * operations.
     *
     * <p> This method performs a blocking <a href="#selop">selection
     * operation</a>.  It returns only after at least one channel is selected,
     * this selector's {@link #wakeup wakeup} method is invoked, or the current
     * thread is interrupted, whichever comes first.  </p>
     *
     * @return  The number of keys, possibly zero,
     *          whose ready-operation sets were updated
     *
     * @throws  IOException
     *          If an I/O error occurs
     *
     * @throws  ClosedSelectorException
     *          If this selector is closed
     */
    public abstract int select() throws IOException;

    /**
     * Causes the first selection operation that has not yet returned to return
     * immediately.
     *
     * <p> If another thread is currently blocked in an invocation of the
     * {@link #select()} or {@link #select(long)} methods then that invocation
     * will return immediately.  If no selection operation is currently in
     * progress then the next invocation of one of these methods will return
     * immediately unless the {@link #selectNow()} method is invoked in the
     * meantime.  In any case the value returned by that invocation may be
     * non-zero.  Subsequent invocations of the {@link #select()} or {@link
     * #select(long)} methods will block as usual unless this method is invoked
     * again in the meantime.
     *
     * <p> Invoking this method more than once between two successive selection
     * operations has the same effect as invoking it just once.  </p>
     *
     * @return  This selector
     */
    public abstract Selector wakeup();

    /**
     * Closes this selector.
     *
     * <p> If a thread is currently blocked in one of this selector's selection
     * methods then it is interrupted as if by invoking the selector's {@link
     * #wakeup wakeup} method.
     *
     * <p> Any uncancelled keys still associated with this selector are
     * invalidated, their channels are deregistered, and any other resources
     * associated with this selector are released.
     *
     * <p> If this selector is already closed then invoking this method has no
     * effect.
     *
     * <p> After a selector is closed, any further attempt to use it, except by
     * invoking this method or the {@link #wakeup wakeup} method, will cause a
     * {@link ClosedSelectorException} to be thrown. </p>
     *
     * @throws  IOException
     *          If an I/O error occurs
     */
    public abstract void close() throws IOException;

}
